/*! @file dbtreeview.cpp
  * @brief Implements class DbTreeView
  * @author AK
  * @date 20.06.2012
  */

#include "defines.h"
#include "mainwindow.h"
#include "dbtreeview.h"

#include <QtGui/QtGui>

/** @brief DbTreeView Constructor
 * @callgraph
 * @callergraph
 */
DbTreeView::DbTreeView(QWidget *parent) :
    QTreeWidget(parent)
{
    connect(this, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
            this, SLOT(_on_itemClickedOrChanged(QTreeWidgetItem*, int)));
    connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
            this, SLOT(_on_itemClickedOrChanged(QTreeWidgetItem*, int)));

    this->setColumnCount(2);
    this->setEditTriggers(QTreeView::SelectedClicked);
    //this->setColumnWidth(0, 150);

    itemcount = 0;
}

/** @brief DbTreeView Destructor
 * @callgraph
 * @callergraph
 */
DbTreeView::~DbTreeView()
{
    itemcount = 0;
}

/*! @brief populates treeView
 * @callgraph
 * @callergraph
 *
 * @param QString filename
 * @param const int ft: filetype
 * @param int fileid: id of file in sqlitedb list
 * @param QString longpath: path including filename
 * @param QList<QString> tables: tables of db file
 */
void DbTreeView::addFile(int fileid,
                         SqliteDb *tmpdb,
                         int maxfile)
{
    filename = tmpdb->getFileName();
    ft = tmpdb->getIntType();
    longpath = tmpdb->longpath;
    tables = tmpdb->getTables();

    int tlcount = 0;                                // counter for toplevel items
    int tcount = 0;                                 // counter for tables in toplevel items (files)
    int fcount = 0;                                 // counter for fields in tables
    int itm;                                        // to identify topLevelItem
    QTreeWidgetItem *file = new QTreeWidgetItem();  // TopLevelItem aka sqlite file
    QList<QTreeWidgetItem *> table;                 // list of tables in file
    //QList<QTreeWidgetItem *> field;                 // list of fields in tables

    maxcount = maxfile;                             // to know when all files are processed

    // append file
    itm = FileType::FT_OTHER - 1;                   // NOTE: no sorting anymore

    this->addTopLevelItem(file);
    _log(Qt::darkGreen, filename);

    file->setText(0, filename);
    file->setText(1, QString::number(fileid));
    file->setToolTip(0, tr("Datenbankdatei: ") + QDir::toNativeSeparators(longpath));
    if (ft > 100 && ft < 300)
        file->setForeground(0, Qt::darkGreen);
    if (ft < -90)
        file->setForeground(0, Qt::darkRed);
    //item->setExpanded(true);
    file->setSelected(true);
    flags = file->flags();
    flags |= Qt::ItemIsSelectable;      // add flag
    flags &= ~(Qt::ItemIsUserCheckable | Qt::ItemIsEditable);  // remove flag
    file->setFlags(flags);

    // append tables to file
    for(tcount=0; tcount<tables.size(); tcount++) {
        QString tmptooltip = tr("Datenbanktabelle: ");
        table.append( new QTreeWidgetItem( file ) );
        _log(Qt::darkBlue, "  > " + tables.at(tcount));
        table.at(tcount)->setText( 0, tables.at(tcount) );
        table.at(tcount)->setText(1, QString::number(tcount));
        if (tmpdb->isTableEmpty(tables.at(tcount))) {
            table.at(tcount)->setForeground(0, Qt::darkYellow);
            tmptooltip = "Leere Datenbanktabelle: ";
        }
        table.at(tcount)->setToolTip(0, tmptooltip
                                        + filename
                                        + " : " + tables.at(tcount));

        // set table flags
        flags = table.at(tcount)->flags();
        flags &= ~(Qt::ItemIsSelectable | Qt::ItemIsEditable); // remove flags
        table.at(tcount)->setFlags(flags);

        // append fields to tables
        QList<QString> fields = tmpdb->getFields(tcount);
        for(fcount=0; fcount<fields.size(); fcount++) {
            QTreeWidgetItem *tmpfield = new QTreeWidgetItem(table.at(tcount));
            tmpfield->setText(0, fields.at(fcount));
            tmpfield->setText(1, QString::number(tcount) + ':' + QString::number(fcount));
            tmpfield->setToolTip(0, tr("Tabellenfeld: ")
                                    + filename
                                    + " : " + tables.at(tcount)
                                    + " : " + fields.at(fcount));
            //set field flags
            flags = tmpfield->flags();
            flags &= ~(Qt::ItemIsSelectable | Qt::ItemIsEditable); // remove flags
            flags |= Qt::ItemIsUserCheckable; // add flag
            tmpfield->setFlags(flags);
            tmpfield->setCheckState(0, Qt::Unchecked);
            _log(Qt::darkGray, "     > " + fields.at(fcount));
        }
    }

    // set TopLevel (= DBFile) properties
    for(tlcount=0; tlcount<this->topLevelItemCount(); ++tlcount) {
        flags = topLevelItem(tlcount)->flags();
        flags |= Qt::ItemIsSelectable;          // add flag
        flags &= ~Qt::ItemIsUserCheckable;      // clear flag
        topLevelItem(tlcount)->setFlags(flags);
        topLevelItem(tlcount)->setSelected(false);
    }

    ++itemcount;
    this->resizeColumnToContents(2);
}

/** @brief clears the TreeView
 * @callgraph
 * @callergraph
 */
void DbTreeView::clearTree()
{
    this->clear();
}

/*! @brief returns a list of checked item names
 * @callgraph
 * @callergraph
 *
 * @returns checkedItemNames QList<QString> of checked items
 */
QList<QString> DbTreeView::getCheckedItemNames()
{
    QList<QString> checkedItemNames;

    Q_FOREACH(QTreeWidgetItem *item, this->selectedItems()) {
        for(int c=0; c<item->childCount(); ++c) {
            if(item->child(c)->isExpanded()) {
                for(int i=0; i<item->child(c)->childCount(); ++i) {
                    if(item->child(c)->child(i)->checkState(0) == Qt::Checked)
                        checkedItemNames << item->child(c)->child(i)->text(0);
                }
            }
        }
    }

    if(checkedItemNames.isEmpty())
        checkedItemNames << "*";

//    qDebug() << "DbTreeView\t|getCheckedItemNames()\t|checkedItemNames:" << checkedItemNames;
    return checkedItemNames;
}

/*! @brief returns details of item *item
 * @callgraph
 * @callergraph
 *
 * @param QTreeWidgetItem *item
 * @returns DbDetails
 */
DbDetails DbTreeView::getDetailsOfItem(QTreeWidgetItem *item)
{
    dbdetails.detailsName = item->text(0);
    dbdetails.detailsId = item->text(1).toInt();

    // check item role
    if(!item->parent()) {
        dbdetails.detailsRole = ItemRole::IR_FILE;
        return dbdetails;
    }
    if(!item->parent()->parent()) {
        dbdetails.detailsRole = ItemRole::IR_TABLE;
        return dbdetails;
    }
    if(!item->parent()->parent()->parent()) {
        dbdetails.detailsRole = ItemRole::IR_FIELD;
        return dbdetails;
    }

    return dbdetails;
}

QString DbTreeView::getSelectedFileName() {
    // just single selection - so first selected item is ok
    Q_FOREACH(QTreeWidgetItem *item, this->selectedItems())
        return item->text(0);

    // should not reach this
    return "ERROR";

}

/*! @brief returns sqlitedb id of selected tree entry
 * @callgraph
 * @callergraph
 *
 * @returns int id: value of sqlitedb id of selected entry
 */
int DbTreeView::getSelectedId() {
    // just single selection - so first selected item is ok
    Q_FOREACH(QTreeWidgetItem *item, this->selectedItems())
        return item->text(1).toInt();

    // should not reach this
    return -99;
}

/*! @brief returns expanded table
 * @callgraph
 * @callergraph
 *
 * @returns table QString: active table in view
 */
QString DbTreeView::getTable() {
    QString activeTable;

    Q_FOREACH(QTreeWidgetItem *item, this->selectedItems())
        for(int cc=0; cc<item->childCount(); ++cc)
            if(item->child(cc)->isExpanded())
                return item->child(cc)->text(0);

    // should not reach this
    return "*";
}

QList<QStringList> DbTreeView::getSettings() {
    QList<QStringList> settings;
    QStringList checkedItems;

    Q_FOREACH(QTreeWidgetItem *item, this->selectedItems()) {
        for (int t = 0; t < item->childCount(); ++t) {
            checkedItems << item->child(t)->text(0);    // first entry is table
            for(int ci=0; ci<item->child(t)->childCount(); ++ci) {
                if(item->child(t)->child(ci)->checkState(0) == Qt::Checked)
                    checkedItems << item->child(t)->child(ci)->text(0);     // rest is checked items
            }
            settings.append(checkedItems);
            checkedItems.clear();
        }
    }
    return settings;
}

/*! @brief checks the items loaded from template
 * @callgraph
 * @callergraph
 *
 * @param QList<QString> lst: List of items to be checked
 */
void DbTreeView::setCheckedItems(QString table, QList<QString> lst)
{
    QList<QTreeWidgetItem*> foundtable;
    QList<QTreeWidgetItem*> founditems;

    foundtable = this->findItems(table,
                                 Qt::MatchFixedString |
                                 Qt::MatchRecursive,
                                 0);
    Q_FOREACH(QString search, lst) {
        founditems << this->findItems(search,
                                      Qt::MatchFixedString |
                                      Qt::MatchRecursive,
                                      0);
    }

    Q_FOREACH(QTreeWidgetItem *item, founditems) {
        if(item->parent()->parent()->text(0) == filename)
            item->setCheckState(0, Qt::Checked);
    }
}

/*! @brief sets the file *item as selected
 * @callgraph
 * @callergraph
 *
 * @param QTreeWidgetItem *item
 * @param int i: not used
 */
void DbTreeView::setSelected(QTreeWidgetItem *item, int i)
{
    _toggleFolded(item, i);
}

/**
 * @brief fold all items
 *
 * @fn DbTreeView::_foldAll
 */
void DbTreeView::_foldAll() {
//    QTreeWidget::collapseAll();
    for(int tl=0; tl<this->topLevelItemCount(); ++tl) {
        for(int t=0; t<topLevelItem(tl)->childCount(); ++t) {
//            for(int f=0; f<topLevelItem(tl)->child(t)->childCount(); ++f)
                //this->topLevelItem(tl)->child(t)->child(f)->setCheckState(0, Qt::Unchecked);
            topLevelItem(tl)->child(t)->setExpanded(false);
        }
        topLevelItem(tl)->setExpanded(false);
    }
}

/*! @brief log Text to LogTextBrowser
 * @callgraph
 * @callergraph
 *
 * @param globalcolor Qt::GlobalColor: color of Log Entry
 * @param message const QString: Message to display
 * @return void
 **/
void DbTreeView::_log (Qt::GlobalColor globalcolor, const QString & message)
{
    Q_EMIT logMe(globalcolor, message);
}

/*! @brief reacts on clicks in the view
 * emits dbChanged() to mainwindow
 * @callgraph
 * @callergraph
 *
 * @param QTreeWidgetItem *item: the clicked item
 * @param int i: not used
  */
void DbTreeView::_on_itemClickedOrChanged(QTreeWidgetItem *item, int i)
{
    Q_UNUSED(i);

    // only do this if all files are in the view
    if(itemcount < maxcount)
        return;

    QString role;
    DbDetails detail = getDetailsOfItem(item);
    if(detail.detailsRole == ItemRole::IR_FILE) {
        //qDebug() << "DbTreeView\t|on_itemClickedOrChanged: IR_FILE" << item->text(0);
        role = "IR_FILE";       // also TopLevelItem
        _toggleFolded(item, i);
        if(filename != item->text(0)){
            filename = item->text(0);
            Q_EMIT dbChanged(item, i);
        }
    }
    else if(detail.detailsRole == ItemRole::IR_TABLE) {
        //qDebug() << "DbTreeView\t|on_itemClickedOrChanged: IR_TABLE" << item->text(0);
        role = "IR_TABLE";
        _toggleFolded(item, i);
        if(filename != item->parent()->text(0)) {
            filename = item->parent()->text(0);
            Q_EMIT dbChanged(item->parent(), i);
        }
    }
    else if(detail.detailsRole == ItemRole::IR_FIELD) {
        //qDebug() << "DbTreeView\t|on_itemClickedOrChanged: IR_FIELD" << item->text(0);
        role = "IR_FIELD";
        _toggleFolded(item, i);
        if(filename != item->parent()->parent()->text(0)) {
            filename = item->parent()->parent()->text(0);
            Q_EMIT dbChanged(item->parent()->parent(), i);
        }
    }
    else
        role = "ERROR";
}

//! @brief Updates treeView on Item double clicked
void DbTreeView::_on_resetItemCount()
{
    itemcount = 0;
}

/*! @brief Updates treeView on Item double clicked
 * It expands all children (tables) of clicked item
 * and hides the others
 * @callgraph
 * @callergraph
 */
int DbTreeView::_setChecked(QTreeWidgetItem *item, int i)
{
    Q_UNUSED(i);

    // fold all children
    _foldAll();

    // unfold just the clicked one
    item->setExpanded(true);
    item->setCheckState(0, Qt::Checked);
    return 0;
}

/*! @brief CheckBox processing if single clicked
 * unchecks all Boxes but the klicked one
 * @callgraph
 * @callergraph
 *
 * @param QTreeWidgetItem *item
 * @param int i: not used
 * @returns int i: 1=topLevel, 0=Childs processed
 */
int DbTreeView::_toggleFolded(QTreeWidgetItem *item, int i)
{
    Q_UNUSED(i);

    DbDetails detail = getDetailsOfItem(item);


    // unfold the clicked one
    if(detail.detailsRole == ItemRole::IR_FILE) {
        _foldAll();
        QTreeWidget::expandItem(item);
        item->setSelected(true);
        this->scrollToItem(item, QAbstractItemView::PositionAtTop);
    }
    else if(detail.detailsRole == ItemRole::IR_TABLE) {
        _foldAll();
        QTreeWidget::expandItem(item->parent());
        QTreeWidget::expandItem(item);
        item->parent()->setSelected(true);
        this->scrollToItem(item, QAbstractItemView::PositionAtTop);
    }
    else if(detail.detailsRole == ItemRole::IR_FIELD) {
        _foldAll();
        QTreeWidget::expandItem(item->parent()->parent());
        QTreeWidget::expandItem(item->parent());
        item->parent()->parent()->setSelected(true);
        this->scrollToItem(item->parent(), QAbstractItemView::PositionAtTop);
    }
    return 0;
}

